package com.gimi.cloud.bbp.client.service.order.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.gimi.cloud.bbp.client.service.mall.MallCartService;
import com.gimi.cloud.bbp.client.service.order.OrderService;
import com.gimi.cloud.bbp.client.service.order.PayService;
import com.gimi.cloud.bbp.client.service.order.SettlementService;
import com.gimi.cloud.bbp.common.constant.RedisKeyConstant;
import com.gimi.cloud.bbp.common.enums.CommonEnume;
import com.gimi.cloud.bbp.common.enums.CommonEnume.PayChannel;
import com.gimi.cloud.bbp.common.enums.ResponseCodeEnum;
import com.gimi.cloud.bbp.common.exception.MsgException;
import com.gimi.cloud.bbp.common.utils.reqhead.Response;
import com.gimi.cloud.bbp.commonService.order.OrderCodeService;
import com.gimi.cloud.bbp.commonService.redis.RedisService;
import com.gimi.cloud.bbp.dao.dao.User.RdExpressInfoMapper;
import com.gimi.cloud.bbp.dao.dao.mall.MallCartDao;
import com.gimi.cloud.bbp.dao.dao.mall.MallPaymentQueueDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderCostDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderExpressDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderGoodsDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderInvoiceDao;
import com.gimi.cloud.bbp.dao.dao.order.OrderLogisticsDao;
import com.gimi.cloud.bbp.dao.dao.prod.EcProdCatModelValueDao;
import com.gimi.cloud.bbp.dto.mall.MallCartDTO;
import com.gimi.cloud.bbp.dto.mall.SettlementDTO;
import com.gimi.cloud.bbp.dto.order.OrderCostDTO;
import com.gimi.cloud.bbp.dto.order.OrderDTO;
import com.gimi.cloud.bbp.dto.order.ShOrderPayinfoDTO;
import com.gimi.cloud.bbp.entity.mall.MallCartEntity;
import com.gimi.cloud.bbp.entity.mall.MallPaymentQueueEntity;
import com.gimi.cloud.bbp.entity.order.OrderCostEntity;
import com.gimi.cloud.bbp.entity.order.OrderEntity;
import com.gimi.cloud.bbp.entity.order.OrderExpressEntity;
import com.gimi.cloud.bbp.entity.order.OrderGoodsEntity;
import com.gimi.cloud.bbp.entity.order.OrderInvoiceEntity;
import com.gimi.cloud.bbp.entity.order.OrderLogisticsEntity;
import com.gimi.cloud.bbp.entity.product.ProductEntity;
import com.gimi.cloud.bbp.entity.product.ProductSkuEntity;
import com.gimi.cloud.bbp.entity.userInfo.RdExpressInfoEntity;
import com.github.pagehelper.PageHelper;

import tk.mybatis.mapper.entity.Example;

/**
 * 结算服务
 * @author 李林峰
 * @version 1.0
 * @Description
 * @create 2018年1月25日
 */
@Service
public class SettlementServiceImpl implements SettlementService {
	
	private static final Logger log = LoggerFactory.getLogger(SettlementServiceImpl.class);
	
	@Autowired private MallCartDao mallCartDao;
	@Autowired private OrderCodeService orderCodeService;
	@Autowired private RedisService redisService;
	@Autowired private OrderDao orderDao;
	@Autowired private OrderCostDao orderCostDao;
	@Autowired private RdExpressInfoMapper expressInfoDao;
	@Autowired private OrderExpressDao orderExpressDao;
	@Autowired private OrderGoodsDao orderGoodsDao;
	@Autowired private OrderInvoiceDao orderInvoiceDao;
	@Autowired private OrderLogisticsDao orderLogisticsDao;
	@Autowired private OrderService orderService;
	@Autowired private MallCartService mallCartService;
	@Autowired private PayService payService;
	@Autowired private EcProdCatModelValueDao prodCatModelValueDao;
	@Autowired private MallPaymentQueueDao mallPaymentQueueDao;

	@Override
	public Response generatingClearingInformation(SettlementDTO settlementInfo) {

		log.info("获取商品详情");
		Map<String, Object> map = new HashMap<>();
		List<MallCartEntity> mallCartLists = mallCartDao.selectMallCartDetailInfor(null,settlementInfo.getCartIdList(),null);
		for (MallCartEntity mallCartEntity : mallCartLists) {
			try {
				ProductSkuEntity prodSku = mallCartEntity.getProdSku();
				String skuValue = prodSku.getSkuValue();
				if (StringUtils.isNotBlank(skuValue)) {
					prodSku.setCatModelValueEntities(prodCatModelValueDao.getModelIdByIds(skuValue));
				}
			} catch (Exception e) {
				throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"商品数据异常");
			}
		}

		log.info("计算商品总金额");
		BigDecimal totalAmount = mallCartDao.statisticalAmount(settlementInfo.getCartIdList());
		BigDecimal freight = BigDecimal.ZERO;
		BigDecimal preferentialAmount = BigDecimal.ZERO;
		
		log.info("获取用户默认地址");
		PageHelper.orderBy("is_default DESC");
		Example example = new Example(RdExpressInfoEntity.class);
		example.createCriteria().andEqualTo("userId", settlementInfo.getUserId()).andEqualTo("isDelete",0);
		List<RdExpressInfoEntity> expressInfos = expressInfoDao.selectByExample(example);
		if (expressInfos!=null&&expressInfos.size()>0) {
			map.put("expressInfo", expressInfos.get(0));
		}
		map.put("mallCartLists", mallCartLists);
		map.put("totalAmount", totalAmount);//商品总金额
		map.put("freight", freight);//运费
		map.put("preferentialAmount", preferentialAmount);//优惠金额
		map.put("settlementAmount", totalAmount.add(freight).add(preferentialAmount));//实付款
		Response response = new Response(ResponseCodeEnum.SUCCESSED);
		response.setRes_data(map);
		return response;
	}

	@Override
	@Transactional
	public Response generatingOrder(SettlementDTO settlementInfo) {
		log.info("开始读取配置表");
		JSONObject orderConfig = redisService.getJSONObjectConfigByKey(RedisKeyConstant.CONFIG_KEY_APP_ORDER_CONFIG);
		if (orderConfig==null) {
			log.error("读取配置失败");
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR);
		}
		Integer confirmDay;
		try {
			confirmDay = orderConfig.getInteger("confirmDay");
			if (confirmDay==null) {
				log.error("订单配置错误,自动确认收货时间confirmDay为空");
				throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"订单配置错误,自动确认收货时间为空");
			}
		} catch (Exception e) {
			log.error("订单配置错误,自动确认收货时间confirmDay格式异常");
			e.printStackTrace();
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"订单配置错误,自动确认收货时间格式异常");
		}
		
		List<Integer> cartIdList = settlementInfo.getCartIdList();
		
		Example example = new Example(MallCartEntity.class);
		example.createCriteria().andIn("cartId", cartIdList);
		List<MallCartEntity> mallCartList = mallCartDao.selectByExample(example);
		log.info("商品总金额计算");
		BigDecimal statisticalAmount = mallCartDao.statisticalAmount(settlementInfo.getCartIdList());
		log.info("获取用户收货地址信息");
		RdExpressInfoEntity expressInfo = expressInfoDao.selectByPrimaryKey(settlementInfo.geteId());
		if (expressInfo==null) {
			log.error("收货地址信息异常");
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"收货地址信息异常");
		}
		log.info("获取订单号");
		String orderCode = orderCodeService.CreateOrderID();
		
		log.info("组装订单参数并保存");
		OrderEntity order = new OrderEntity();
		order.setUserId(settlementInfo.getUserId());
		order.setOrderCode(orderCode);
		order.setConfirmDay(confirmDay);
		order.setActivityId(settlementInfo.getActivityId());
		order.setOrderSource(settlementInfo.getOrderSource());
		order.setOrderType(settlementInfo.getOrderType());
		order.setStatus(CommonEnume.OrderStatus.A01.name());
		order.setPayStatus(CommonEnume.PayStatus.nopay.name());
		orderDao.baseInsert(order);
		
		Integer oId = order.getoId();
		
		for (MallCartEntity mallCartEntity : mallCartList) {
			log.info("查询商品详情");
			List<MallCartEntity> selectMallCartDetailInfor = mallCartDao.selectMallCartDetailInfor(null,null,mallCartEntity.getCartId());
			if (selectMallCartDetailInfor==null||selectMallCartDetailInfor.size()<=0) {
				continue;
			}
			MallCartEntity mallCart = selectMallCartDetailInfor.get(0);
			ProductEntity product = mallCart.getProdSku().getProduct();
			ProductSkuEntity prodSku = mallCart.getProdSku();
			BigDecimal skuPrice = prodSku.getSkuPrice();
			Integer cartNum = mallCart.getCartNum();
			String prodName = product.getProdName();
			log.info(prodName+"单品总金额计算");
			BigDecimal total = skuPrice.multiply(new BigDecimal(cartNum));

			log.info("组装订单商品详情并保存");
			OrderGoodsEntity orderGoods = new OrderGoodsEntity();
			orderGoods.setoId(oId);
			orderGoods.setOrderCode(orderCode);
			orderGoods.setProdName(prodName);
			orderGoods.setProdBrandName(product.getProdBrandName());
			orderGoods.setProdId(mallCart.getProdId());
			orderGoods.setProdCode(product.getMerchantProdBarCode());
			orderGoods.setSkuId(mallCart.getSkuId());
			orderGoods.setPrice(skuPrice);
			orderGoods.setCost(cartNum);
			orderGoods.setTotal(total);
			orderGoodsDao.baseInsert(orderGoods);
		}
		
		log.info("组装订单费用详情并保存");
		OrderCostEntity orderCost = new OrderCostEntity();
		orderCost.setoId(oId);
		orderCost.setOrderCode(order.getOrderCode());
		orderCost.setGoodsTotal(statisticalAmount);
		orderCost.setOrderTotal(statisticalAmount);
		orderCost.setPayTotal(statisticalAmount);
		orderCostDao.baseInsert(orderCost);
		
		log.info("组装订单收货地址详情并保存");
		OrderExpressEntity orderExpress = new OrderExpressEntity();
		BeanUtils.copyProperties(expressInfo, orderExpress);
		orderExpress.setoId(oId);
		orderExpress.setOrderCode(orderCode);
		orderExpressDao.baseInsert(orderExpress);
		
		log.info("组装订单发票详情并保存");
		OrderInvoiceEntity orderInvoice = new OrderInvoiceEntity();
		orderInvoice.setoId(oId);
		orderInvoice.setOrderCode(orderCode);
		orderInvoiceDao.baseInsert(orderInvoice);
		
		log.info("组装订单物流信息并保存");
		OrderLogisticsEntity orderLogistics = new OrderLogisticsEntity();
		orderLogistics.setoId(oId);
		orderLogistics.setOrderCode(orderCode);
		orderLogisticsDao.baseInsert(orderLogistics);
		
		mallCartService.deleteShoppingCartByCartIdList(cartIdList);
		orderService.recordOrderOperLog(oId,"用户提交订单");//记录订单操作日志
		
		Response response = new Response(ResponseCodeEnum.SUCCESSED);
		Map<String, Object> map = new HashMap<>();
		OrderDTO orderDTO = new OrderDTO();
		orderDTO.setOId(oId);
		map.put("orderInfo", orderDTO);
		response.setRes_data(map);
		return response;
	}

	@Override
	public Response submissionOfPaymentStatus(ShOrderPayinfoDTO settlementInfo) {
		return null;
	}

	@Override
	public Response buyDirect(MallCartDTO mallCart) {
		Integer cartID = mallCartService.saveShoppingCart(mallCart, MallCartService.MODIFY);
		SettlementDTO settlementInfo = new SettlementDTO();
		
		List<Integer> cartIdList = new ArrayList<>();
		cartIdList.add(cartID);
		settlementInfo.setCartIdList(cartIdList);
		settlementInfo.setUserId(mallCart.getUserId());
		
		return generatingClearingInformation(settlementInfo);
	}

	@Override
	public Response getPaymentParameters(OrderDTO orderDTO) {
		Response response = new Response(ResponseCodeEnum.SUCCESSED);
		Map<String, Object> map = new HashMap<>();
		Integer oId = orderDTO.getOId();
		OrderEntity order = orderDao.selectByPrimaryKey(oId);
		BigDecimal payTotal = orderCostDao.queryBy("o_id", oId).getPayTotal();

		if (CommonEnume.PayStatus.pay.name().equals(order.getPayStatus())) {
			throw new MsgException(ResponseCodeEnum.ORDER_ERROR,"订单已支付,请勿重复发起支付请求");
		}

		try {
			PayChannel payChannel = CommonEnume.PayChannel.valueOf(orderDTO.getPayChannel());
			switch (payChannel) {
			case ZFB:
				String alipayParameter = creatAlipayParameter(order,payTotal);
				map.put("alipayParameter", alipayParameter);
				break;
			default:
				throw new MsgException(ResponseCodeEnum.PARAMETER_ERROR,"支付渠道参数错误");
			}
		} catch (MsgException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"创建支付参数异常");
		}
		response.setRes_data(map);
		return response;
	}

	private String creatAlipayParameter(OrderEntity order, BigDecimal payTotal) throws AlipayApiException {
		Integer oId = order.getoId();
		List<OrderGoodsEntity> orderGoods = orderGoodsDao.queryListBy("o_id", oId);
		StringBuilder stringBuilder = new StringBuilder();
		for (OrderGoodsEntity orderGoodsEntity : orderGoods) {
			stringBuilder.append(orderGoodsEntity.getProdName());
			stringBuilder.append(",");
		}

		log.info("读取配置表aliPayConfig");
		JSONObject aliPayConfig = redisService.getJSONObjectConfigByKey(RedisKeyConstant.ALI_PAY_CONFIG);
		JSONObject appPayModel = aliPayConfig.getJSONObject("AppPayModel");
		String orderCode = order.getOrderCode();
		
		log.info("解析订单有效时间配置");
		String timeoutExpress = appPayModel.getString("timeoutExpress");
		int lastindex = timeoutExpress.length()-1;
		char charAt = timeoutExpress.charAt(lastindex);
		Integer timeoutnum = null;
		try {
			timeoutnum = Integer.valueOf(timeoutExpress.substring(0, lastindex));
		} catch (Exception e) {
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"订单有效时间配置错误："+timeoutExpress);
		}
		Date now = new Date();
		Date pdExpectedEndTime;
		switch (charAt) {
		case 'm'://m-分钟
			pdExpectedEndTime = DateUtils.addMinutes(now, timeoutnum);
			break;
		case 'h'://h-小时
			pdExpectedEndTime = DateUtils.addHours(now, timeoutnum);
			break;
		case 'd'://d-天
			pdExpectedEndTime = DateUtils.addDays(now, timeoutnum);
			break;
		default:
			throw new MsgException(ResponseCodeEnum.SERVICE_ERROR,"订单有效时间配置错误："+timeoutExpress);
		}

		log.info("组装支付宝请求参数");
		/*
		 * SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式
		 * (model和biz_content同时存在的情况下取biz_content)。
		 */
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody(stringBuilder.toString());
		model.setSubject(appPayModel.getString("subject"));
		model.setOutTradeNo(orderCode);
		model.setTimeoutExpress(timeoutExpress);
		model.setTotalAmount(payTotal.toString());
		model.setProductCode(appPayModel.getString("productCode"));
		
		String aliPayOrderString = payService.getAliPayOrderString(model);
		
		MallPaymentQueueEntity mallPaymentQueueEntity = mallPaymentQueueDao.queryBy("o_id", oId);
		
		if (mallPaymentQueueEntity==null) {
			log.info("添加支付队列");
			MallPaymentQueueEntity record = new MallPaymentQueueEntity();
			record.setoId(oId);
			record.setOrderCode(orderCode);
			record.setPdStartTime(now);
			record.setPdExpectedEndTime(pdExpectedEndTime);
			record.setPdPayStatus(0);
			mallPaymentQueueDao.baseInsert(record);
		}

		return aliPayOrderString;
	}

	@Override
	public Response getOrderPayAmount(OrderDTO order) {
		OrderCostEntity queryBy = orderCostDao.queryBy("o_id", order.getOId());
		Response response = new Response(ResponseCodeEnum.SUCCESSED);
		OrderCostDTO orderCostDTO = new OrderCostDTO();
		orderCostDTO.setoId(queryBy.getoId());
		orderCostDTO.setPayTotal(queryBy.getPayTotal());
		Map<String, Object> map = new HashMap<>();
		map.put("orderCost", orderCostDTO);
		response.setRes_data(map);
		return response;
	}

}